package MyGui;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.text.NumberFormat;
import java.util.Vector;

import Element.AbsElem;
import Element.Line;
import Element.Geom.*;
import DistSys.*;

public abstract class AbsElemInfoDlg extends MyDlgFrame{ //JDialog {
    protected static final int GAP = 4;

    protected AbsElem elem;
    protected boolean bModified = false;

    private Vector vDataPanel = new Vector();
    private Component focusOwner = null;
    private boolean bBlockVerifyFocus = false;

    protected Font font = null;
    protected NumberFormat nf = NumberFormat.getNumberInstance();
    {
        nf.setMaximumFractionDigits(4);
        nf.setGroupingUsed(false);
    }

    public AbsElemInfoDlg(MainFrame parent, String title, boolean modal,
                          AbsElem elem) {
        super(parent, title);//, modal);
        this.elem = elem;
    }

    public void setCurrentElem(AbsElem elem) {
        this.elem = elem;
    }

    protected static final int PANEL_DATA = 1;  //Last 4 digits in 0x: 0001
    protected static final int PANEL_CHECK= 2;  //Last 4 digits in 0x: 0010
    protected static final int PANEL_EDIT = 4;  //Last 4 digits in 0x: 0100

    protected JPanel createPanel(int[] indices, String title, int style) {
        JPanel panel = new DataPanel(indices, title, style);
        vDataPanel.add(panel);
        return panel;
    }

    protected void recreateAllPanels() {
        for (int i = 0; i < vDataPanel.size(); i++) {
            ((DataPanel)vDataPanel.elementAt(i)).recreatePanel();
        }
    }

    protected void updateAllPanels(){
        for (int i = 0; i < vDataPanel.size(); i++) {
            ((DataPanel)vDataPanel.elementAt(i)).updatePanel();
        }
        bModified = false;
    }

    /*=============================================
    Implement FocusListener
    =============================================*/
    protected FocusAdapter focusListener = new FocusAdapter() {
        public void focusGained(FocusEvent e) { focusOwner = getFocusOwner(); }
        public void focusLost(FocusEvent e) { }
    };

    protected boolean verifyFocus() {
        if (bBlockVerifyFocus)
            return false;
        else if (focusOwner != null && focusOwner instanceof JComponent) {
            JComponent input = (JComponent)focusOwner;
            InputVerifier verifier = input.getInputVerifier();
            if (verifier != null && !verifier.shouldYieldFocus(input)) {
                return false;
            }
            focusOwner = null;
        }
        return true;
    }

    /*======================================
    DataPanel subclass
    ======================================*/
    class DataPanel extends JPanel {
        private int[] aiIndex;
        private int iStyle;

        private JLabel[]  aLabel;
        private JCheckBox[] aCheckBox;
        private JTextField[] aTextField;

        public DataPanel(int[] indices, String title, int style) {
            aiIndex = indices;
            iStyle = style;
            if ((iStyle & PANEL_DATA) == 0) //it's a result panel
                iStyle = 0;                 //guarantee all bits are 0's
            else if ((iStyle & PANEL_CHECK) != 0) //has check
                iStyle |= PANEL_EDIT;       //guarantee it is also editable

            int iCount = aiIndex.length;
            aLabel = new JLabel[iCount];
            aTextField = new JTextField[iCount];
            InputVerifier verifier = null;
            ActionListener listener = null;
            if ((iStyle & PANEL_DATA) != 0) {
                verifier = new DataSaveVerifier(aTextField, aiIndex);
                if ((iStyle & PANEL_CHECK) != 0) {
                    aCheckBox = new JCheckBox[iCount];
                    listener = new CheckSaveActionListener(aCheckBox,
                        aTextField, aiIndex);
                }
            }
            for(int i = 0; i < iCount; i++){
                if (aiIndex[i] >= 0) {
                    aLabel[i] = new JLabel();
                    aTextField[i] = new JTextField("", 5);
                    if (font != null) {
                        aLabel[i].setFont(font);
                        aTextField[i].setFont(font);
                    }
                    aTextField[i].addFocusListener(focusListener);
                    if ((iStyle & PANEL_DATA) != 0) {
                        aTextField[i].setInputVerifier(verifier);
                        if ((iStyle & PANEL_CHECK) != 0) {
                            aCheckBox[i] = new JCheckBox();
                            aCheckBox[i].addActionListener(listener);
                            //add MouseListener: Dbl click to restore auto value
                            if( aiIndex[i] == AbsElem.DATA_LENGTH ){
                                aLabel[i].setForeground( Color.blue );
                                aLabel[i].addMouseListener(
                                    new LableMouseListener(
                                        aCheckBox[i],aTextField[i],aiIndex[i]));
                            }
                        } else if ((iStyle & PANEL_EDIT) == 0)
                            aTextField[i].setEditable(false);
                    }
                }
            }

            setLayout(MyDlgFrame.gridBagLayout);
            setBorder(BorderFactory.createTitledBorder(
                BorderFactory.createEtchedBorder(), title));
        }//end of constructor

        public void recreatePanel() {
            removeAll();

            GridBagConstraints c = new GridBagConstraints();
            c.fill = GridBagConstraints.BOTH;
            c.gridy = 0;
            c.insets = new Insets(0, GAP, GAP, 0);
            for (int i = 0; i < aiIndex.length; i++) {
                if (aiIndex[i] < 0) {
                    // add a separation
                    if (c.gridy > 0 && c.insets.top == 0)
                        c.insets.top = 3*GAP;
                } else if (((iStyle & PANEL_DATA) != 0 && elem.getDataExists(aiIndex[i])) ||
                           ((iStyle & PANEL_DATA) == 0 && elem.getResultExists(aiIndex[i]))) {
                    c.gridx = 0;
                    c.insets.right = 0; c.weightx = 0;

                    if ((iStyle & PANEL_CHECK) != 0) {
                        add(aCheckBox[i], c); c.gridx++; c.insets.left = 0;
                    }
                    c.weightx=1; c.weighty=1;
                    add(aTextField[i], c); c.gridx++;
                    c.weightx=0; c.weighty=0;
                    c.insets.left = GAP; c.weightx = 1;
                    add(aLabel[i], c);
                    c.gridy++; c.insets.top = 0;
                }
            }
        }//end of recreatePanel()

        public void updatePanel() {
            AbsElemGeom geom = elem.getElemGeomObj();

            for (int i = 0; i < aiIndex.length; i++) {
                int index = aiIndex[i];
                if (index < 0) continue; //it is just a separator

                //process all non-separator [check + textfields + lables]
                //process lables
                String sLabel;
                if ((iStyle & PANEL_DATA) != 0) {
                    sLabel = SysConst.getDataFieldFromValueIndex(index);
                    if (geom instanceof LineGeom) {
                        if (index == AbsElem.DATA_LENGTH)
                            sLabel += ": " + Sys.prjInfo.getUnitInString();
                        else if (index == AbsElem.DATA_TEMP_FAULT ||
                                 index == AbsElem.DATA_SUST_FAULT ||
                                 index == AbsElem.DATA_OPEN_CKT ||
                                 index == AbsElem.DATA_RESISTANCE ||
                                 index == AbsElem.DATA_REACTANCE ||
                                 index == AbsElem.DATA_SHUNT_COND ||
                                 index == AbsElem.DATA_SHUNT_SUCEP ||
                                 index == AbsElem.DATA_CAPITAL_COST ||
                                 index == AbsElem.DATA_OM_COST) {
                            sLabel += "/" + Sys.prjInfo.getUnitInString();
                        }
                    }
                } else {
                    sLabel = SysConst.getResultFieldFromValueIndex(index);
                }
                aLabel[i].setText(sLabel);

                //process textfields and checks(if needed)
                if ((iStyle & PANEL_DATA) != 0) {
                    if ((iStyle & PANEL_CHECK) != 0) {
                        boolean bFlag = elem.getCustomizedFlag(index);
                        if (index == AbsElem.DATA_LENGTH &&
                            geom instanceof LineGeom) {
                            if ( elem.getAutoFlag( AbsElem.DATA_LENGTH ) ) {
                                aCheckBox[i].setBorderPainted(true);
                                bFlag = false;
                            } else {
                                aCheckBox[i].setBorderPainted(false);
                            }
                        }
                        aCheckBox[i].setSelected(bFlag);
                        aTextField[i].setEnabled(bFlag);
                    }
                    aTextField[i].setText(nf.format(elem.getData(index)));
                } else {
                    aTextField[i].setText(nf.format(elem.getResult(index)));
                }
                aTextField[i].setCaretPosition(0);
            }//end of for loop
        }//end of updatePanel()
    }//end of class DataPanel

    /*======================================
    DataSaveVerifier subclass
    ======================================*/
    class DataSaveVerifier extends InputVerifier {
        private JTextField[] tfs;
        private int[] indices;
        public DataSaveVerifier(JTextField[] tfs, int[] indices) {
            this.tfs = tfs;
            this.indices = indices;
        }

        public boolean verify(JComponent input) {
            for (int i = 0; i < tfs.length; i++) {
                if (input == tfs[i]) {
                    bBlockVerifyFocus = true;
                    try {
                        double value = Double.parseDouble(tfs[i].getText());
                        //SysConst.MappedIndex mappedIndex =
                        //    SysConst.mapData(indices[i]);
                        if (value!=elem.getData( indices[i])){
                            bModified = true;
                            elem.setData( indices[i], value);
                            if (indices[i] == AbsElem.DATA_ZONE) {
                                Sys.prjInfo.addZoneIfUnexisted(value, null);
                            }
                        }
                        return true;
                    } catch(NumberFormatException e) {
                        JOptionPane.showMessageDialog( null,
                            "Please input a number!");
                    } catch(IllegalArgumentException e) {
                        JOptionPane.showMessageDialog( null, e.getMessage());
                    } finally {
                        bBlockVerifyFocus = false;
                    }
                    break;
                }
            }
            return false;
        }
    }

    /*======================================
    CheckSaveActionListener subclass
    ======================================*/
    class CheckSaveActionListener implements ActionListener {
        private JTextField[] tfs;
        private JCheckBox[] checks;
        private int[] indices;
        public CheckSaveActionListener(JCheckBox[] checks, JTextField[] tfs,
                                       int[] indices) {
            this.checks = checks;
            this.tfs = tfs;
            this.indices = indices;
        }
        public void actionPerformed(ActionEvent evt){
            AbsElemGeom geom = elem.getElemGeomObj();
            Object obj = evt.getSource();
            for (int i = 0; i < checks.length; i++) {
                if (obj == checks[i]) {
                    bModified = true;

                    if (geom instanceof LineGeom &&
                        indices[i] == AbsElem.DATA_LENGTH &&
                        checks[i].isBorderPainted()) {
                        // length checkbox with default value
                        checks[i].setBorderPainted(false);
                        checks[i].setSelected(true);
                        elem.setCustomizedFlag( AbsElem.DATA_LENGTH, false);
                        //((LineGeom)geom).isAutoValue = false;
                    }

                    //SysConst.MappedIndex mappedIndex =
                    //    SysConst.mapData(indices[i]);
                    boolean bCustomized = checks[i].isSelected();
                    //elem.setCustomizedFromMappedDataIndex( mappedIndex, bCustomized);
                    elem.setCustomizedFlag( indices[i], bCustomized);

                    tfs[i].setEnabled(bCustomized);
                    if (!bCustomized && elem.getDftTemp() != null) {
                        double value = elem.getDftTemp().
                            getData(indices[i]);
                        elem.setData(indices[i], value);
                        tfs[i].setText(nf.format(value));
                    }
                    break;
                }//end of if (find the actionReceiver)
            }//end of for
        }//end of actionPerformed
    };

    class LableMouseListener extends MouseAdapter{
        private JCheckBox check;
        private JTextField tf;
        private int index;
        private int cntr=0;
        public LableMouseListener(JCheckBox check, JTextField tf, int index){
            super();
            this.check = check;
            this.tf = tf;
            this.index = index;
        }

        public void mouseClicked(MouseEvent evt){
            if( evt.getClickCount()==2 &&
                evt.getModifiers()==InputEvent.BUTTON1_MASK){
                //left mouse double clicked
                double value;
                elem.setAutoFlag( index, true ); //Now only AbsElem.DATA_LENGTH
                check.setBorderPainted(true);
                check.setSelected(false);
                if( index == AbsElem.DATA_LENGTH && elem instanceof Line ){
                    ((Line)elem).setLengthToAutoValue();
                    tf.setText( nf.format( elem.getLength() ) );
                    tf.setEnabled( false );
                    //System.out.println("here - " + (cntr++) );
                }
            }
        }
    };
}